{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
-- needs different instances on ghc8 and on ghc9

module Cardano.Node.Tracing.Tracers
  ( mkDispatchTracers
  ) where

import           Cardano.Logging
import qualified Cardano.Network.Diffusion as Cardano.Diffusion
import           Cardano.Node.Protocol.Types (SomeConsensusProtocol)
import           Cardano.Node.Queries (NodeKernelData)
import           Cardano.Node.TraceConstraints
import           Cardano.Node.Tracing
import           Cardano.Node.Tracing.Consistency (checkNodeTraceConfiguration')
import           Cardano.Node.Tracing.Formatting ()
import qualified Cardano.Node.Tracing.StateRep as SR
import           Cardano.Node.Tracing.Tracers.BlockReplayProgress
import           Cardano.Node.Tracing.Tracers.ChainDB
import           Cardano.Node.Tracing.Tracers.Consensus
import           Cardano.Node.Tracing.Tracers.Diffusion ()
import           Cardano.Node.Tracing.Tracers.ForgingStats (calcForgeStats)
import           Cardano.Node.Tracing.Tracers.KESInfo
import           Cardano.Node.Tracing.Tracers.LedgerMetrics ()
import           Cardano.Node.Tracing.Tracers.NodeToClient ()
import           Cardano.Node.Tracing.Tracers.NodeToNode ()
import           Cardano.Node.Tracing.Tracers.NodeVersion (getNodeVersion)
import           Cardano.Node.Tracing.Tracers.P2P ()
import           Cardano.Node.Tracing.Tracers.Shutdown ()
import           Cardano.Node.Tracing.Tracers.Startup ()
import           Ouroboros.Consensus.Ledger.Inspect (LedgerEvent)
import           Ouroboros.Consensus.MiniProtocol.ChainSync.Client (TraceChainSyncClientEvent)
import qualified Ouroboros.Consensus.Network.NodeToClient as NodeToClient
import qualified Ouroboros.Consensus.Network.NodeToClient as NtC
import qualified Ouroboros.Consensus.Network.NodeToNode as NodeToNode
import qualified Ouroboros.Consensus.Network.NodeToNode as NtN
import           Ouroboros.Consensus.Node.GSM
import qualified Ouroboros.Consensus.Node.Run as Consensus
import qualified Ouroboros.Consensus.Node.Tracers as Consensus
import qualified Ouroboros.Consensus.Storage.ChainDB as ChainDB
import qualified Ouroboros.Consensus.Storage.LedgerDB as LedgerDB
import           Ouroboros.Network.Block
import qualified Ouroboros.Network.BlockFetch.ClientState as BlockFetch
import           Ouroboros.Network.ConnectionId (ConnectionId)
import qualified Ouroboros.Network.Diffusion as Diffusion
import           Ouroboros.Network.NodeToClient (LocalAddress)
import           Ouroboros.Network.NodeToNode (RemoteAddress)

import           Codec.CBOR.Read (DeserialiseFailure)
import           Control.Monad (unless)
import           "contra-tracer" Control.Tracer (Tracer (..))
import           Data.Proxy (Proxy (..))
import           Network.Mux.Trace (TraceLabelPeer (..))

-- | Construct tracers for all system components.
--
mkDispatchTracers
  :: forall blk .
  ( Consensus.RunNode blk
  , TraceConstraints blk
  , LogFormatting (LedgerEvent blk)
  , LogFormatting
    (TraceLabelPeer
      (ConnectionId RemoteAddress) (TraceChainSyncClientEvent blk))
  , LogFormatting (TraceGsmEvent (Tip blk))
  , MetaTrace (TraceGsmEvent (Tip blk))
  )
  => NodeKernelData blk
  -> Trace IO FormattedMessage
  -> Trace IO FormattedMessage
  -> Maybe (Trace IO FormattedMessage)
  -> Trace IO DataPoint
  -> TraceConfig
  -> SomeConsensusProtocol
  -> IO (Tracers RemoteAddress LocalAddress blk IO)

mkDispatchTracers nodeKernel trBase trForward mbTrEKG trDataPoint trConfig p = do

    configReflection <- emptyConfigReflection

    !nodeInfoDP <- mkDataPointTracer trDataPoint
    configureTracers configReflection trConfig [nodeInfoDP]

    !nodeStartupInfoDP <- mkDataPointTracer trDataPoint
    configureTracers configReflection trConfig [nodeStartupInfoDP]

    !nodeStateDP <- mkDataPointTracer trDataPoint
    configureTracers configReflection trConfig [nodeStateDP]

    !stateTr <- mkCardanoTracer trBase trForward mbTrEKG ["NodeState"]
    configureTracers configReflection trConfig [stateTr]

    !resourcesTr <- mkCardanoTracer trBase trForward mbTrEKG []
    configureTracers configReflection trConfig [resourcesTr]

    !ledgerMetricsTr <- mkCardanoTracer trBase trForward mbTrEKG []
    configureTracers configReflection trConfig [ledgerMetricsTr]

    !startupTr <- mkCardanoTracer trBase trForward mbTrEKG ["Startup"]
    configureTracers configReflection trConfig [startupTr]

    !shutdownTr <- mkCardanoTracer trBase trForward mbTrEKG ["Shutdown"]
    configureTracers configReflection trConfig  [shutdownTr]

    !chainDBTr <- mkCardanoTracer' trBase trForward mbTrEKG ["ChainDB"]
                                    withAddedToCurrentChainEmptyLimited
    configureTracers configReflection trConfig [chainDBTr]

    !nodeVersionTr <- mkCardanoTracer trBase trForward mbTrEKG ["Version"]
    configureTracers configReflection trConfig  [nodeVersionTr]

    -- Filter out replayed blocks for this tracer
    let chainDBTr' = filterTrace
                      (\case (_, ChainDB.TraceLedgerDBEvent
                                            (LedgerDB.LedgerReplayEvent (LedgerDB.TraceReplayProgressEvent
                                                                        (LedgerDB.ReplayedBlock {})))) -> False
                             (_, _) -> True)
                      chainDBTr


    !replayBlockTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["ChainDB", "ReplayBlock"]
    configureTracers configReflection trConfig [replayBlockTr]

    -- This tracer handles replayed blocks specially
    !replayBlockTr' <- withReplayedBlock replayBlockTr


    !consensusTr <-
      mkConsensusTracers configReflection trBase trForward mbTrEKG trDataPoint trConfig nodeKernel

    !nodeToClientTr <-
      mkNodeToClientTracers configReflection trBase trForward mbTrEKG trDataPoint trConfig

    !nodeToNodeTr <-
      mkNodeToNodeTracers configReflection trBase trForward mbTrEKG trDataPoint trConfig

    !(diffusionTr :: Cardano.Diffusion.CardanoTracers IO) <-
      mkDiffusionTracers configReflection trBase trForward mbTrEKG trDataPoint trConfig

    !churnModeTr <- mkCardanoTracer trBase trForward mbTrEKG ["Net", "PeerSelection", "ChurnMode"]
    configureTracers configReflection trConfig [churnModeTr]

    traceTracerInfo trBase trForward configReflection

    let warnings = checkNodeTraceConfiguration' trConfig
    unless (null warnings) $
      traceConfigWarnings trBase trForward warnings

    traceEffectiveConfiguration trBase trForward trConfig

    traceWith nodeVersionTr getNodeVersion

    pure Tracers
      {
        chainDBTracer = Tracer (traceWith chainDBTr')
                      <> Tracer (traceWith replayBlockTr')
                      <> Tracer (SR.traceNodeStateChainDB p nodeStateDP)
      , consensusTracers = consensusTr
      , churnModeTracer = Tracer (traceWith churnModeTr)
      , nodeToClientTracers = nodeToClientTr
      , nodeToNodeTracers = nodeToNodeTr
      , diffusionTracers = diffusionTr
      , startupTracer   = Tracer (traceWith startupTr)
                         <> Tracer (SR.traceNodeStateStartup nodeStateDP)
      , shutdownTracer  = Tracer (traceWith shutdownTr)
                         <> Tracer (SR.traceNodeStateShutdown nodeStateDP)
      , nodeInfoTracer  = Tracer (traceWith nodeInfoDP)
      , nodeStartupInfoTracer = Tracer (traceWith nodeStartupInfoDP)
      , nodeStateTracer = Tracer (traceWith stateTr)
                          <> Tracer (traceWith nodeStateDP)
      , nodeVersionTracer = Tracer (traceWith nodeVersionTr)
      , resourcesTracer = Tracer (traceWith resourcesTr)
      , ledgerMetricsTracer = Tracer (traceWith ledgerMetricsTr)
    }

mkConsensusTracers :: forall blk.
  ( Consensus.RunNode blk
  , TraceConstraints blk
  , LogFormatting (TraceLabelPeer
                    (ConnectionId RemoteAddress) (TraceChainSyncClientEvent blk))
  , LogFormatting (TraceGsmEvent (Tip blk))
  , MetaTrace (TraceGsmEvent (Tip blk))
  )
  => ConfigReflection
  -> Trace IO FormattedMessage
  -> Trace IO FormattedMessage
  -> Maybe (Trace IO FormattedMessage)
  -> Trace IO DataPoint
  -> TraceConfig
  -> NodeKernelData blk
  -> IO (Consensus.Tracers IO (ConnectionId RemoteAddress) (ConnectionId LocalAddress) blk)
mkConsensusTracers configReflection trBase trForward mbTrEKG _trDataPoint trConfig _nodeKernel = do
    !chainSyncClientTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                 ["ChainSync", "Client"]
    configureTracers configReflection trConfig [chainSyncClientTr]
    !chainSyncServerHeaderTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["ChainSync", "ServerHeader"]
    configureTracers configReflection trConfig [chainSyncServerHeaderTr]

    -- Special chainSync server metrics
    -- any server header event advances the counter
    let chainSyncServerHeaderMetricsTr =
           contramap
              (const
                (FormattedMetrics
                  [CounterM "ChainSync.HeadersServed" Nothing]))
              (mkMetricsTracer mbTrEKG)

    !chainSyncServerBlockTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["ChainSync", "ServerBlock"]
    configureTracers configReflection trConfig [chainSyncServerBlockTr]

    !consensusSanityCheckTr <- mkCardanoTracer
                 trBase trForward mbTrEKG
                 ["Consensus", "SanityCheck"]
    configureTracers configReflection trConfig [consensusSanityCheckTr]

    !blockFetchDecisionTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockFetch", "Decision"]
    configureTracers configReflection trConfig [blockFetchDecisionTr]

    !blockFetchClientTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockFetch", "Client"]
    configureTracers configReflection trConfig [blockFetchClientTr]

    -- Special blockFetch client metrics, send directly to EKG
    !blockFetchClientMetricsTr <- do
        tr1 <- foldTraceM (\cm lc -> pure . calculateBlockFetchClientMetrics cm lc) initialClientMetrics
                    (metricsFormatter
                      (mkMetricsTracer mbTrEKG))
        pure $ filterTrace (\ (_, TraceLabelPeer _ m) -> case m of
                                              BlockFetch.CompletedBlockFetch {} -> True
                                              _ -> False)
                 tr1

    !blockFetchServerTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockFetch", "Server"]
    configureTracers configReflection trConfig [blockFetchServerTr]

    !servedBlockLatestTr <- servedBlockLatest mbTrEKG

    !forgeKESInfoTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Forge", "StateInfo"]
    configureTracers configReflection trConfig [forgeKESInfoTr]

    !txInboundTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["TxSubmission", "TxInbound"]
    configureTracers configReflection trConfig [txInboundTr]

    !txOutboundTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["TxSubmission", "TxOutbound"]
    configureTracers configReflection trConfig [txOutboundTr]

    !localTxSubmissionServerTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["TxSubmission", "LocalServer"]
    configureTracers configReflection trConfig [localTxSubmissionServerTr]

    !mempoolTr   <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Mempool"]
    configureTracers configReflection trConfig [mempoolTr]

    !forgeTr    <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Forge", "Loop"]
    configureTracers configReflection trConfig [forgeTr]

    !forgeStatsTr <- mkCardanoTracer'
                trBase trForward mbTrEKG
                ["Forge", "Stats"]
                calcForgeStats
    configureTracers configReflection trConfig [forgeStatsTr]

    !blockchainTimeTr   <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockchainTime"]
    configureTracers configReflection trConfig [blockchainTimeTr]

    !keepAliveClientTr  <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net"]
    configureTracers configReflection trConfig [keepAliveClientTr]

    !consensusStartupErrorTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Consensus", "Startup"]
    configureTracers configReflection trConfig [consensusStartupErrorTr]

    !consensusGddTr <- mkCardanoTracer
                 trBase trForward mbTrEKG
                 ["Consensus", "GDD"]
    configureTracers configReflection trConfig [consensusGddTr]

    !consensusGsmTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Consensus", "GSM"]
    configureTracers configReflection trConfig [consensusGsmTr]

    !consensusCsjTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Consensus", "CSJ"]
    configureTracers configReflection trConfig [consensusCsjTr]

    !consensusKesAgentTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Consensus", "KESAgent"]
    configureTracers configReflection trConfig [consensusKesAgentTr]

    !consensusDbfTr <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Consensus", "DevotedBlockFetch"]
    configureTracers configReflection trConfig [consensusDbfTr]

    pure $ Consensus.Tracers
      { Consensus.chainSyncClientTracer = Tracer $
          traceWith chainSyncClientTr
      , Consensus.chainSyncServerHeaderTracer = Tracer $
            traceWith chainSyncServerHeaderTr
           <> traceWith chainSyncServerHeaderMetricsTr
      , Consensus.chainSyncServerBlockTracer = Tracer $
          traceWith chainSyncServerBlockTr
      , Consensus.consensusSanityCheckTracer = Tracer $
          traceWith consensusSanityCheckTr
      , Consensus.blockFetchDecisionTracer = Tracer $
          traceWith blockFetchDecisionTr
      , Consensus.blockFetchClientTracer = Tracer $
          traceWith blockFetchClientTr
           <> traceWith blockFetchClientMetricsTr
      , Consensus.blockFetchServerTracer = Tracer $
          traceWith blockFetchServerTr
          <> traceWith servedBlockLatestTr
      , Consensus.forgeStateInfoTracer = Tracer $
          traceWith (traceAsKESInfo (Proxy @blk) forgeKESInfoTr)
      , Consensus.gddTracer = Tracer $
          traceWith consensusGddTr
      , Consensus.txInboundTracer = Tracer $
           traceWith txInboundTr
      , Consensus.txOutboundTracer = Tracer $
          traceWith txOutboundTr
      , Consensus.localTxSubmissionServerTracer = Tracer $
          traceWith localTxSubmissionServerTr
      , Consensus.mempoolTracer = Tracer $
          traceWith mempoolTr
      , Consensus.forgeTracer =
           Tracer (\(Consensus.TraceLabelCreds _ x) -> traceWith forgeTr x)
           <>
           Tracer (\(Consensus.TraceLabelCreds _ x) -> traceWith forgeStatsTr x)
      , Consensus.blockchainTimeTracer = Tracer $
          traceWith blockchainTimeTr
      , Consensus.keepAliveClientTracer = Tracer $
          traceWith keepAliveClientTr
      , Consensus.consensusErrorTracer = Tracer $
          traceWith consensusStartupErrorTr . ConsensusStartupException
      , Consensus.gsmTracer = Tracer $
          traceWith consensusGsmTr
      , Consensus.csjTracer = Tracer $
          traceWith consensusCsjTr
      , Consensus.dbfTracer = Tracer $
          traceWith consensusDbfTr
      , Consensus.kesAgentTracer = Tracer $
          traceWith consensusKesAgentTr
      }

mkNodeToClientTracers :: forall blk.
     Consensus.RunNode blk
  => ConfigReflection
  -> Trace IO FormattedMessage
  -> Trace IO FormattedMessage
  -> Maybe (Trace IO FormattedMessage)
  -> Trace IO DataPoint
  -> TraceConfig
  -> IO (NodeToClient.Tracers IO (ConnectionId LocalAddress) blk DeserialiseFailure)
mkNodeToClientTracers configReflection trBase trForward mbTrEKG _trDataPoint trConfig = do
    !chainSyncTr <-
      mkCardanoTracer
        trBase trForward mbTrEKG
        ["ChainSync", "Local"]
    configureTracers configReflection trConfig [chainSyncTr]

    !txMonitorTr <-
      mkCardanoTracer
        trBase trForward mbTrEKG
        ["TxSubmission", "MonitorClient"]
    configureTracers configReflection trConfig [txMonitorTr]

    !txSubmissionTr <-
      mkCardanoTracer
        trBase trForward mbTrEKG
        ["TxSubmission", "Local"]
    configureTracers configReflection trConfig [txSubmissionTr]

    !stateQueryTr <-
      mkCardanoTracer
        trBase trForward mbTrEKG
        ["StateQueryServer"]
    configureTracers configReflection trConfig [stateQueryTr]

    pure $ NtC.Tracers
      { NtC.tChainSyncTracer = Tracer $
          traceWith chainSyncTr
      , NtC.tTxMonitorTracer = Tracer $
          traceWith txMonitorTr
      , NtC.tTxSubmissionTracer = Tracer $
          traceWith txSubmissionTr
      , NtC.tStateQueryTracer = Tracer $
          traceWith stateQueryTr
      }

mkNodeToNodeTracers :: forall blk.
  ( Consensus.RunNode blk
  , TraceConstraints blk)
  => ConfigReflection
  -> Trace IO FormattedMessage
  -> Trace IO FormattedMessage
  -> Maybe (Trace IO FormattedMessage)
  -> Trace IO DataPoint
  -> TraceConfig
  -> IO (NodeToNode.Tracers IO RemoteAddress blk DeserialiseFailure)
mkNodeToNodeTracers configReflection trBase trForward mbTrEKG _trDataPoint trConfig = do

    !chainSyncTracer <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["ChainSync", "Remote"]
    configureTracers configReflection trConfig [chainSyncTracer]

    !chainSyncSerialisedTr <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["ChainSync", "Remote", "Serialised"]
    configureTracers configReflection trConfig [chainSyncSerialisedTr]

    !blockFetchTr  <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockFetch", "Remote"]
    configureTracers configReflection trConfig [blockFetchTr]

    !blockFetchSerialisedTr <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["BlockFetch", "Remote", "Serialised"]
    configureTracers configReflection trConfig [blockFetchSerialisedTr]

    !txSubmission2Tracer  <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["TxSubmission", "Remote"]
    configureTracers configReflection trConfig [txSubmission2Tracer]

    !keepAliveTracer  <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["KeepAlive", "Remote"]
    configureTracers configReflection trConfig [keepAliveTracer]

    !peerSharingTracer  <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["PeerSharing", "Remote"]
    configureTracers configReflection trConfig [peerSharingTracer]

    pure $ NtN.Tracers
      { NtN.tChainSyncTracer = Tracer $
          traceWith chainSyncTracer
      , NtN.tChainSyncSerialisedTracer = Tracer $
          traceWith chainSyncSerialisedTr
      , NtN.tBlockFetchTracer = Tracer $
          traceWith blockFetchTr
      , NtN.tBlockFetchSerialisedTracer = Tracer $
          traceWith blockFetchSerialisedTr
      , NtN.tTxSubmission2Tracer = Tracer $
          traceWith txSubmission2Tracer
      , NtN.tKeepAliveTracer = Tracer $
          traceWith keepAliveTracer
      , NtN.tPeerSharingTracer = Tracer $
          traceWith peerSharingTracer
      }

mkDiffusionTracers
  :: ConfigReflection
  -> Trace IO FormattedMessage
  -> Trace IO FormattedMessage
  -> Maybe (Trace IO FormattedMessage)
  -> Trace IO DataPoint
  -> TraceConfig
  -> IO (Cardano.Diffusion.CardanoTracers IO)
mkDiffusionTracers configReflection trBase trForward mbTrEKG _trDataPoint trConfig = do

    !dtMuxTr   <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Remote"]
    configureTracers configReflection trConfig [dtMuxTr]

    !dtChannelTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Remote", "Channel"]
    configureTracers configReflection trConfig [dtChannelTracer]

    !dtBearerTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Remote", "Bearer"]
    configureTracers configReflection trConfig [dtBearerTracer]

    !dtHandshakeTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Handshake", "Remote"]
    configureTracers configReflection trConfig [dtHandshakeTracer]

    !dtLocalMuxTr   <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Local"]
    configureTracers configReflection trConfig [dtLocalMuxTr]

    !dtLocalChannelTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Local", "Channel"]
    configureTracers configReflection trConfig [dtLocalChannelTracer]

    !dtLocalBearerTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Mux", "Local", "Bearer"]
    configureTracers configReflection trConfig [dtLocalBearerTracer]

    !dtLocalHandshakeTracer <- mkCardanoTracer
                trBase trForward mbTrEKG
                ["Net", "Handshake", "Local"]
    configureTracers configReflection trConfig [dtLocalHandshakeTracer]

    !dtDiffusionInitializationTr   <-  mkCardanoTracer
                trBase trForward mbTrEKG
                ["Startup", "DiffusionInit"]
    configureTracers configReflection trConfig [dtDiffusionInitializationTr]

    !localRootPeersTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Peers", "LocalRoot"]
    configureTracers configReflection trConfig [localRootPeersTr]

    !publicRootPeersTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Peers", "PublicRoot"]
    configureTracers configReflection trConfig [publicRootPeersTr]

    !peerSelectionTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "PeerSelection", "Selection"]
    configureTracers configReflection trConfig [peerSelectionTr]

    !debugPeerSelectionTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "PeerSelection", "Initiator"]
    configureTracers configReflection trConfig [debugPeerSelectionTr]

    !debugPeerSelectionResponderTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "PeerSelection", "Responder"]
    configureTracers configReflection trConfig [debugPeerSelectionResponderTr]

    !peerSelectionCountersTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "PeerSelection"]
    configureTracers configReflection trConfig [peerSelectionCountersTr]

    !churnCountersTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Churn"]
    configureTracers configReflection trConfig [churnCountersTr]

    !peerSelectionActionsTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "PeerSelection", "Actions"]
    configureTracers configReflection trConfig [peerSelectionActionsTr]

    !connectionManagerTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "ConnectionManager", "Remote"]
    configureTracers configReflection trConfig [connectionManagerTr]

    !connectionManagerTransitionsTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "ConnectionManager", "Transition"]
    configureTracers configReflection trConfig [connectionManagerTransitionsTr]

    !serverTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Server", "Remote"]
    configureTracers configReflection trConfig [serverTr]

    !inboundGovernorTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "InboundGovernor", "Remote"]
    configureTracers configReflection trConfig [inboundGovernorTr]

    !localInboundGovernorTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "InboundGovernor", "Local"]
    configureTracers configReflection trConfig [localInboundGovernorTr]

    !inboundGovernorTransitionsTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "InboundGovernor", "Transition"]
    configureTracers configReflection trConfig [inboundGovernorTransitionsTr]

    !localConnectionManagerTr  <-  mkCardanoTracer
      trBase trForward Nothing -- never conflate metrics of the same name with those originating from `connectionManagerTr`
      ["Net", "ConnectionManager", "Local"]
    configureTracers configReflection trConfig [localConnectionManagerTr]

    !localServerTr  <-  mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Server", "Local"]
    configureTracers configReflection trConfig [localServerTr]

    !dtLedgerPeersTr   <- mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "Peers", "Ledger"]
    configureTracers configReflection trConfig [dtLedgerPeersTr]

    !dtDnsTr  <- mkCardanoTracer
      trBase trForward mbTrEKG
      ["Net", "DNS"]
    configureTracers configReflection trConfig [dtDnsTr]

    pure $ Diffusion.Tracers
       { Diffusion.dtMuxTracer = Tracer $
           traceWith dtMuxTr
       , Diffusion.dtChannelTracer = Tracer $
           traceWith dtChannelTracer
       , Diffusion.dtBearerTracer = Tracer $
           traceWith dtBearerTracer
       , Diffusion.dtHandshakeTracer = Tracer $
           traceWith dtHandshakeTracer
       , Diffusion.dtLocalMuxTracer = Tracer $
           traceWith dtLocalMuxTr
       , Diffusion.dtLocalChannelTracer = Tracer $
           traceWith dtLocalChannelTracer
       , Diffusion.dtLocalBearerTracer = Tracer $
           traceWith dtLocalBearerTracer
       , Diffusion.dtLocalHandshakeTracer = Tracer $
           traceWith dtLocalHandshakeTracer
       , Diffusion.dtDiffusionTracer = Tracer $
           traceWith dtDiffusionInitializationTr
       , Diffusion.dtTraceLocalRootPeersTracer = Tracer $
           traceWith localRootPeersTr
       , Diffusion.dtTracePublicRootPeersTracer = Tracer $
           traceWith publicRootPeersTr
       , Diffusion.dtTracePeerSelectionTracer = Tracer $
           traceWith peerSelectionTr
       , Diffusion.dtDebugPeerSelectionInitiatorTracer = Tracer $
           traceWith debugPeerSelectionTr
       , Diffusion.dtDebugPeerSelectionInitiatorResponderTracer = Tracer $
           traceWith debugPeerSelectionResponderTr
       , Diffusion.dtTracePeerSelectionCounters = Tracer $
           traceWith peerSelectionCountersTr
       , Diffusion.dtTraceChurnCounters = Tracer $
           traceWith churnCountersTr
       , Diffusion.dtPeerSelectionActionsTracer = Tracer $
           traceWith peerSelectionActionsTr
       , Diffusion.dtConnectionManagerTracer = Tracer $
           traceWith connectionManagerTr
       , Diffusion.dtConnectionManagerTransitionTracer = Tracer $
           traceWith connectionManagerTransitionsTr
       , Diffusion.dtServerTracer = Tracer $
           traceWith serverTr
       , Diffusion.dtInboundGovernorTracer = Tracer $
           traceWith inboundGovernorTr
       , Diffusion.dtLocalInboundGovernorTracer = Tracer $
           traceWith localInboundGovernorTr
       , Diffusion.dtInboundGovernorTransitionTracer = Tracer $
           traceWith inboundGovernorTransitionsTr
       , Diffusion.dtLocalConnectionManagerTracer =  Tracer $
           traceWith localConnectionManagerTr
       , Diffusion.dtLocalServerTracer = Tracer $
           traceWith localServerTr
       , Diffusion.dtTraceLedgerPeersTracer = Tracer $
           traceWith dtLedgerPeersTr
       , Diffusion.dtDnsTracer = Tracer $
           traceWith dtDnsTr
       }
